package control;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;

import IOoperation.XMLcontroler;

import commands.AddBuilding;
import commands.AddGate;
import commands.AddQuaryCrane;
import commands.AddRailMountedGantry;
import commands.AddReachStacker;
import commands.AddRoadTruck;
import commands.AddRubberTiredGantry;
import commands.AddStack;
import commands.AddTerminal;
import commands.AddTerminalTruck;

import core.Coordinate;
import core.Property;
import factory.ComponentInterface;

/**
 * 
 * @author albertcsani
 * 
 */
public enum ComponentProvider {
	INSTANCE;
	private List<ComponentInterface> listComp;
	private List<Property> properties;
	private ComponentInterface compToPlace = null;
	private ComponentInterface compSelected = null;
	private ComponentPlacement compPlace;
	private Composite editComp;
	private TableViewer viewer;

	/**
	 * alapertelmezett konstruktor
	 */
	private ComponentProvider() {
		listComp = new ArrayList<ComponentInterface>();
		properties = new ArrayList<Property>();
		compPlace = new ComponentPlacement(listComp);
	}

	/**
	 * 
	 * @return a kivalaszott Component vagy null ha nincs semmi kivalasztva
	 */

	public ComponentInterface getSelected() {
		return compSelected;
	}

	/**
	 * 
	 * @param comp
	 *            lementi a RoadEditorWiev-nak a compozitjat hogy tudjon
	 *            redrowot hivni ra
	 */
	public void setComposite(Composite mParent) {
		editComp = mParent;

	}

	/**
	 * public void setComposite(Composite comp) { editComp = comp; } /**
	 * 
	 * @param viewer
	 *            a viwer-je a properties viewnak
	 */
	public void setPropView(TableViewer viewer) {
		this.viewer = viewer;
	}

	/**
	 * Frissiti a RoadEditorWiev-t
	 */
	public void redrawEditor() {
		editComp.redraw();
		editComp.update();
	}

	/**
	 * Frissiti a PropertiesWiev-t
	 */
	public void redrawProperties() {
		if (compSelected != null) {
			properties.clear();
			properties.add(new Property("Name", compSelected.getClass().getSimpleName()));

			properties.add(new Property("Pozition X", String.valueOf(compSelected.getPosition().getX())));
			properties.add(new Property("Pozition Y", String.valueOf(compSelected.getPosition().getY())));
			properties.add(new Property("Size X", String.valueOf(compSelected.getSize().getX())));
			properties.add(new Property("Size Y", String.valueOf(compSelected.getSize().getY())));

			String or = "";
			if (compSelected.getOrientation() == SWT.UP) {
				or = "UP";
			} else if (compSelected.getOrientation() == SWT.DOWN) {
				or = "DOWN";
			} else if (compSelected.getOrientation() == SWT.RIGHT) {
				or = "RIGHT";
			} else if (compSelected.getOrientation() == SWT.LEFT) {
				or = "LEFT";
			}

			properties.add(new Property("Orientation", or));
		} else {
			properties.clear();
		}
		viewer.refresh();
	}

	/**
	 * A propertView-feltoltesehez kell hasznalni
	 * 
	 * @return egy lista Property elemekkel
	 */
	public List<Property> getProperties() {
		return properties;
	}

	/**
	 * Torol egy elemet a listabol es a kepernyorol
	 * 
	 * @param toDel
	 *            a torolendo ComponentInterface
	 * @return true ha sikerult, false ha nem
	 */
	public boolean remove(ComponentInterface toDel) {
		if (compPlace.isDeletable(toDel)) {
			listComp.remove(toDel);
			compSelected = null;
			redrawEditor();
			compPlace.addListToMatrix(listComp);
			return true;
		}
		return false;
	}

	/**
	 * Beallitja a "kivalasztasnak" az X,Y koordinatan levo ComponentInterfacet
	 * 
	 * @param x
	 *            X koordinata (e.x/zoomfaktor)
	 * @param y
	 *            Y koordinata (e.y/zoomfaktor)
	 */
	public void selectComponent(int x, int y) {
		compSelected = compPlace.getCompByCoordinate(new Coordinate(x, y));
	}

	/**
	 * Beallitja kivalasztottnak a kivant komponenst
	 * 
	 * @param sel
	 *            ComponentInterface
	 */
	public void setSelectedComponent(ComponentInterface sel) {
		compSelected = sel;
	}

	/**
	 * Leelenorzi hogy lerakhato-e a compToPlace ComponentInterface
	 * 
	 * @return true ha lerakhato false ha nem
	 */
	public boolean isPlaceble() {
		return compPlace.isPlaceable(compToPlace);
	}

	/**
	 * Beallitja a compToPlacet a comp-ra es a compSelected-et null-ra
	 * 
	 * @param comp
	 *            a ComponentsTreeWiev-bol kivalasztott ComponentInterface
	 */
	public void setComponent(ComponentInterface comp) {
		compToPlace = comp;
		compSelected = null;
	}

	/**
	 * 
	 * @return a "lerakando" ComponentInterface
	 */
	public ComponentInterface getCompToPlace() {
		return compToPlace;
	}

	/**
	 * 
	 * @param compDown
	 *            az elhelyezendo objektum neve
	 * @param compUp
	 *            objektumok neve, amelyek ala kell keruljon az elhelyezendo
	 *            objektum
	 * @param compToPlace
	 *            az elhelyezendo objektum
	 */
	private void addUnderComponent(String compDown, String[] compUp, ComponentInterface compToPlace) {
		boolean isCompInList = false;
		Iterator<ComponentInterface> it = listComp.iterator();
		wasPlaced: while (it.hasNext()) {
			ComponentInterface component = (ComponentInterface) it.next();
			for (int i = 0; i < compUp.length; i++) {
				if (component.getClass().getSimpleName().equals(compUp[i])) {
					listComp.add(listComp.indexOf(component), compToPlace);
					isCompInList = true;
					break wasPlaced;
				}
			}
		}
		if (!isCompInList) {
			listComp.add(compToPlace);
		}
	}

	/**
	 * A compToPlace -t brerakja a listaba a neki megfelelo helyre.
	 */
	public void addComponent() {
		if (compToPlace.getClass().getSimpleName().equals("Vessel")) {
			String[] upperComps = { "QuaryCrane" };
			addUnderComponent("Vessel", upperComps, compToPlace);
		} else if (compToPlace.getClass().getSimpleName().equals("TerminalTruck")) {
			String[] upperComps = { "RailMountedGantry", "RubberTiredGantry" };
			addUnderComponent("TerminalTruck", upperComps, compToPlace);
		} else if (compToPlace.getClass().getSimpleName().equals("Stack")) {
			String[] upperComps = { "TerminalTruck" };
			addUnderComponent("Stack", upperComps, compToPlace);
		} else if (compToPlace.getClass().getSimpleName().equals("Terminal")) {
			String[] upperComps = { "Terminal" };
			addUnderComponent("Terminal", upperComps, compToPlace);
		} else {
			listComp.add(compToPlace);
		}
		compPlace.addCompToMatrix(compToPlace);
		addComponentByName(getCompToPlace().getClass().getSimpleName());
	}

	/**
	 * Berakja a parameterbe levo ComponentInterface-t a listaba a megfelelo
	 * helyre
	 * 
	 * @param compInt
	 *            ComponentInterface amit beakarunk rakni a listaba.
	 */
	public void addComponent(ComponentInterface compInt) {
		if (compInt.getClass().getSimpleName().equals("Vessel")) {
			String[] upperComps = { "QuaryCrane" };
			addUnderComponent("Vessel", upperComps, compInt);
		} else if (compInt.getClass().getSimpleName().equals("TerminalTruck")) {
			String[] upperComps = { "RailMountedGantry", "RubberTiredGantry" };
			addUnderComponent("TerminalTruck", upperComps, compInt);
		} else if (compInt.getClass().getSimpleName().equals("Stack")) {
			String[] upperComps = { "TerminalTruck" };
			addUnderComponent("Stack", upperComps, compInt);
		} else if (compInt.getClass().getSimpleName().equals("Terminal")) {
			String[] upperComps = { "Terminal" };
			addUnderComponent("Terminal", upperComps, compInt);
		} else {
			listComp.add(compInt);
		}
		compPlace.addCompToMatrix(compInt);
	}

	/**
	 * Meghivja a name parameterben megadott Commandot
	 * 
	 * @param name
	 *            A command amit kell futtason
	 * 
	 */
	public void addComponentByName(String name) {
		if (name.equals("[Quary Crane]") || name.equals("QuaryCrane")) {
			new AddQuaryCrane().execute(null);
		} else if (name.equals("[Building]") || name.equals("Building")) {
			new AddBuilding().execute(null);
		} else if (name.equals("[Rubber Tired Gantry]") || name.equals("RubberTiredGantry")) {
			new AddRubberTiredGantry().execute(null);
		} else if (name.equals("[Gate]") || name.equals("Gate")) {
			new AddGate().execute(null);
		} else if (name.equals("[Terminal Truck]") || name.equals("TerminalTruck")) {
			new AddTerminalTruck().execute(null);
		} else if (name.equals("[Road Truck]") || name.equals("RoadTruck")) {
			new AddRoadTruck().execute(null);
		} else if (name.equals("[Reach Stacker]") || name.equals("ReachStacker")) {
			new AddReachStacker().execute(null);
		} else if (name.equals("[Terminal]") || name.equals("Terminal")) {
			new AddTerminal().execute(null);
		} else if (name.equals("[Stack]") || name.equals("Stack")) {
			new AddStack().execute(null);
		} else if (name.equals("[Rail Mounted Gantry]") || name.equals("RailMountedGantry")) {
			new AddRailMountedGantry().execute(null);
		} else if (name.equals("[Vessel]") || name.equals("Vessel")) {
			new AddRailMountedGantry().execute(null);
		}
	}

	/**
	 * Lementi a kikotonket a fileName parameterben megadott xml fajlba
	 * 
	 * @param fileName
	 *            Fajl amibe ment
	 */
	public void save(String fileName) {
		new XMLcontroler().exportToXml(listComp, fileName);
	}

	/**
	 * Betolt egy kikotot a fileName parameterben megadott xml fajlbol
	 * 
	 * @param fileName
	 *            fajl amibol betolt
	 */
	public void load(String fileName) {
		List<ComponentInterface> listComp2 = new XMLcontroler().importFromXml(fileName);
		if (listComp2.size() > 2) {
			listComp = listComp2;
		}
		compPlace.addListToMatrix(listComp);
		redrawEditor();
	}

	/**
	 * Visszaterit egy listat ComponentInterfacekkel, ezeket tartalmazza a
	 * kikoto
	 * 
	 * @return a kikoto elemeit tartalmazo lista
	 */
	public List<ComponentInterface> getComponents() {
		return listComp;
	}

}